library(readr)
library(tidyverse)
library(data.table)
library(kableExtra)
library(here)
The images are taken with the 360-degree camera RICOH THETA S (see here). The camera has two inbuilt lenses, producing a 360-degree image.
To capture the sorrounding as good as possible and to cover the hemisphere in all directions around the plot centre, the camera is held vertically above the head.
Naming of the images should be consistent as CityClusterPlotnumber_Imagenumber (e.g. MDLDT01_01).
knitr::include_graphics(here("raw_data/img/plotdesign.png"))
The images are converted into binary images and gap fraction is calculated automatically using ImageJ and the hemispherical_2.0 macro.
ImageJ is a Java-based image processing program developed at the National Institutes of Health and the Laboratory for Optical and Computational Instrumentation (LOCI, University of Wisconsin). It is open-source and can be downloaded for free here.
Download ImageJ
Hemispherical_2.0 is a macro for ImageJ that batch processes large quantities of both digital hemispherical and non-hemispherical canopy photographs at comparatively faster computational speeds. It was developed at the Institute of Forest Inventory and Remote Sensing in Goettigen. It can be downloaded here.
Download Hemispherical_2.0
The manual is included in the download above and can also be seen seperately here.
For processing the images with ImageJ and the hemispherical_2.0 macro the images have to be masked in a first step. In ImageJ:
knitr::include_graphics(here("raw_data/img/MDLDT04_1_xmp_e.jpg"))
knitr::include_graphics(here("output_data/img/MDLDT04_1_xmp_e_T.jpg"))
results_MDL <- read_csv(here("output_data/doc/hemiphotos_results_MDL.csv"))
results_MAW <- read_csv(here("output_data/doc/hemiphotos_results_MAW.csv"))
results_MGZ <- read_csv(here("output_data/doc/hemiphotos_results_MGZ.csv"))
# merge data
hemi <- bind_rows(results_MDL, results_MAW, results_MGZ)
# get plot data from image name
hemi <- hemi %>%
mutate(city = as.factor(substr(photo, start = 1, stop = 3)),
cluster = as.factor(substr(photo, start = 4, stop = 5)),
plot = as.factor(substr(photo, start = 6, stop = 7)))
head(hemi) %>%
select(-city, -cluster, -plot) %>%
kable(escape = F) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), font_size = 12, fixed_thead = T)
| Index | photo | no_of_gaps | gap_area | gap_fraction |
|---|---|---|---|---|
| 0 | MDLDT01_1_xmp_e.jpg | 974 | 3350562 | 43.036 |
| 1 | MDLDT01_2_xmp_e.jpg | 2817 | 1063230 | 13.657 |
| 2 | MDLDT01_3_xmp_e.jpg | 1621 | 4741994 | 60.908 |
| 3 | MDLDT01_4_xmp_e.jpg | 612 | 4207448 | 54.042 |
| 4 | MDLDT02_1_xmp_e.jpg | 1219 | 4710816 | 60.508 |
| 5 | MDLDT02_2_xmp_e.jpg | 1193 | 4571665 | 58.720 |
Output data can be analyzed and plotted by city and cluster for example.
The gap fraction is a metric for the openness of the plots, hence plots in the city or in forested sites should have lower gap fractions than agricultural dominated sites
p <- ggplot(hemi, aes(x=cluster, y=gap_fraction)) +
geom_boxplot() +
facet_grid(city ~ .) +
theme_bw()
print(p)
The number of gaps might be an indicator for structural diversity. As this is dependend on a lot of factors this metric should be interpreted carefully.
p <- ggplot(hemi, aes(x=cluster, y=no_of_gaps)) +
geom_boxplot() +
facet_grid(city ~ .) +
theme_bw()
print(p)
In a further step this data can be merged with observations from the field or remote sensing data to enable a deeper anaylsis.
# read bird data
birddata <- read_csv(here("raw_data/doc/2019_Pointcount_data_MGZ_MAW.csv"),
col_types = cols(Day = col_skip(), Elevation = col_skip(),
Month = col_skip(), Sight = col_character(),
Temperature = col_skip(), Year = col_skip(),
hours = col_skip(), minutes = col_skip()))
# group by plot
hemi.grouped <- hemi %>%
group_by(city, cluster, plot) %>%
summarise(no_of_images= n(),
mean_gap_fraction = mean(gap_fraction, na.rm = T),
mean_no_of_gaps = mean(no_of_gaps, na.rm = T),
mean_gap_area = mean(gap_area, na.rm = T))
# get plot data from image name
birddata <- birddata %>%
mutate(city = as.factor(substr(Point, start = 1, stop = 3)),
cluster = as.factor(substr(Point, start = 4, stop = 5)),
plot = as.factor(substr(Point, start = 6, stop = 7)))
hemibird <- merge(hemi.grouped, birddata, by=c("city","cluster", "plot"))
p <- hemibird %>%
group_by(city, cluster, plot) %>%
summarise(no_of_species = n_distinct(English_Name),
bird_count = sum(Count),
mean_no_of_gaps = mean(mean_no_of_gaps, na.rm = T),
mean_gap_area = mean(mean_gap_area, na.rm = T),
mean_gap_fraction = mean(mean_gap_fraction, na.rm = T)) %>%
ggplot(aes(x=mean_gap_fraction, y=bird_count)) +
geom_point(aes(color= city)) +
theme_bw()
print(p)
p <- hemibird %>%
group_by(city, cluster, plot) %>%
summarise(no_of_species = n_distinct(English_Name),
bird_count = sum(Count),
mean_no_of_gaps = mean(mean_no_of_gaps, na.rm = T),
mean_gap_area = mean(mean_gap_area, na.rm = T),
mean_gap_fraction = mean(mean_gap_fraction, na.rm = T)) %>%
ggplot(aes(x=mean_no_of_gaps, y=no_of_species)) +
geom_point(aes(color= city)) +
theme_bw()
print(p)